﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;

namespace DotNetCommon.Extensions;

/// <summary>
/// <see cref="Dictionary{TKey, TValue}"/> 扩展类
/// </summary>
public static class DictionaryExtensions
{
    /// <summary>
    /// 从<paramref name="dictionary"/>中获取值，如果指定的 <paramref name="key"/> 不存在的话，就将<paramref name="value"/>添加进去
    /// </summary>
    public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, TValue value)
    {
        if (dictionary.TryGetValue(key, out var result)) { return result; }

        dictionary[key] = value;
        return value;
    }

    /// <summary>
    /// 从<paramref name="dictionary"/>中获取值，如果指定的 <paramref name="key"/> 不存在的话，就调用<paramref name="valueCreator"/>生成值并添加进去
    /// </summary>
    public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> valueCreator)
    {
        if (dictionary.TryGetValue(key, out var result)) { return result; }

        var value = valueCreator();
        dictionary[key] = value;
        result = value;
        return result;
    }

    /// <summary>
    /// 从<paramref name="dictionary"/>中获取值，如果指定的 <paramref name="key"/> 不存在的话，返回指定的 <paramref name="defaultValue"/>
    /// </summary>
    public static TValue GetOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary,
        TKey key, TValue defaultValue = default)
            => dictionary.TryGetValue(key, out var value) ? value : defaultValue;

    /// <summary>
    /// 将给定的字典 <paramref name="pairsToAdd"/> 中的数据添加到当前字典中
    /// </summary>
    public static void Add<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, IDictionary<TKey, TValue> pairsToAdd)
    {
        foreach (var pair in pairsToAdd)
        {
            dictionary.Add(pair.Key, pair.Value);
        }
    }

    /// <summary>
    /// 比较当前字典和给定的字典 <paramref name="right"/> 是否相等，使用<paramref name="valueComparer"/>比较器对集合中的元素进行比较
    /// </summary>
    public static bool Equals<TKey, TValue>(this IDictionary<TKey, TValue> left,
        IDictionary<TKey, TValue> right, IEqualityComparer<TValue> valueComparer = default)
            => Equals((IReadOnlyDictionary<TKey, TValue>)left, (IReadOnlyDictionary<TKey, TValue>)right, valueComparer);

    /// <summary>
    /// 将<see cref="NameValueCollection"/> 转换成字典
    /// </summary>
    public static Dictionary<string, string> ToDictionary(this NameValueCollection namedValueCollection)
        => namedValueCollection.AllKeys.ToDictionary(key => key, key => namedValueCollection[key]);

    /// <summary>
    /// 将当前字典转换为线程安全的字典
    /// </summary>
    public static ConcurrentDictionary<TKey, TValue> ToConcurrentDictionary<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary) =>
        new ConcurrentDictionary<TKey, TValue>(dictionary);

    /// <summary>
    /// 将当前只读字典转换为线程安全的字典
    /// </summary>
    public static ConcurrentDictionary<TKey, TValue> ToConcurrentDictionary<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary,
        IEqualityComparer<TKey> comparer)
            => new ConcurrentDictionary<TKey, TValue>(dictionary, comparer);

    /// <summary>
    /// 使用指定的比较器将当前的字典与指定的字典<paramref name="right"/>进行比较
    /// </summary>
    public static bool Equals<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> left,
        IReadOnlyDictionary<TKey, TValue> right, IEqualityComparer<TValue> valueComparer = default)
    {
        if (left == right) { return true; }
        if (left is null || right == null) { return false; }
        if (left.Count != right.Count) { return false; }
        if (left.Count == 0) { return true; }

        var comparer = valueComparer ?? EqualityComparer<TValue>.Default;

        if (left is Dictionary<TKey, TValue> leftConcrete)
        {
            foreach (var pair in leftConcrete)
            {
                if (!KeyValueExists(pair.Key, pair.Value, right, comparer)) { return false; }
            }
        }
        else if (right is Dictionary<TKey, TValue> rightConcrete)
        {
            foreach (var pair in rightConcrete)
            {
                if (!KeyValueExists(pair.Key, pair.Value, left, comparer)) { return false; }
            }
        }
        else
        {
            foreach (var pair in left)
            {
                if (!KeyValueExists(pair.Key, pair.Value, right, comparer)) { return false; }
            }
        }
        return true;
    }

    private static bool KeyValueExists<TKey, TValue>(
        TKey key, TValue value, IReadOnlyDictionary<TKey, TValue> dictionary, IEqualityComparer<TValue> comparer)
            => dictionary.TryGetValue(key, out var rightVal) && comparer.Equals(value, rightVal);

    #region Fluent风格 Dictionary<TKey, TValue> IDictionary<TKey, TValue> SetFluent/RemoveFluent/ClearFluent
    /// <summary>
    /// Fluent风格: 从字典中移除项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// <item>如果key不存在,则跳过</item>
    /// </list>
    /// </remarks>
    public static Dictionary<TKey, TValue> RemoveFluent<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key)
    {
        AssertUtil.NotNull(dic);
        dic.Remove(key);
        return dic;
    }
    /// <summary>
    /// Fluent风格: 从字典中移除项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// <item>如果key不存在,则跳过</item>
    /// </list>
    /// </remarks>
    public static IDictionary<TKey, TValue> RemoveFluent<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key)
    {
        AssertUtil.NotNull(dic);
        dic.Remove(key);
        return dic;
    }

    /// <summary>
    /// Fluent风格: 向字典中添加或更新项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static Dictionary<TKey, TValue> SetFluent<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key, TValue value)
    {
        AssertUtil.NotNull(dic);
        dic[key] = value;
        return dic;
    }

    /// <summary>
    /// Fluent风格: 向字典中添加或更新项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static IDictionary<TKey, TValue> SetFluent<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key, TValue value)
    {
        AssertUtil.NotNull(dic);
        dic[key] = value;
        return dic;
    }

    /// <summary>
    /// Fluent风格: 向字典中添加或更新项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// <item>如果setValFunc为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static Dictionary<TKey, TValue> SetUpdateFluent<TKey, TValue>(this Dictionary<TKey, TValue> dic, TKey key, Func<TValue, TValue> setValFunc)
    {
        AssertUtil.NotNull(dic);
        AssertUtil.NotNull(setValFunc);
        dic.TryGetValue(key, out TValue value);
        dic[key] = setValFunc(value);
        return dic;
    }

    /// <summary>
    /// Fluent风格: 向字典中添加或更新项,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// <item>如果setValFunc为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static IDictionary<TKey, TValue> SetUpdateFluent<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key, Func<TValue, TValue> setValFunc)
    {
        AssertUtil.NotNull(dic);
        AssertUtil.NotNull(setValFunc);
        dic.TryGetValue(key, out TValue value);
        dic[key] = setValFunc(value);
        return dic;
    }

    /// <summary>
    /// Fluent风格: 清空字典,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static Dictionary<TKey, TValue> ClearFluent<TKey, TValue>(this Dictionary<TKey, TValue> dic)
    {
        AssertUtil.NotNull(dic);
        dic.Clear();
        return dic;
    }

    /// <summary>
    /// Fluent风格: 清空字典,并返回自身
    /// </summary>
    /// <remarks>
    /// 注意:
    /// <list type="bullet">
    /// <item>如果字典为null,抛出异常</item>
    /// </list>
    /// </remarks>
    public static IDictionary<TKey, TValue> ClearFluent<TKey, TValue>(this IDictionary<TKey, TValue> dic)
    {
        AssertUtil.NotNull(dic);
        dic.Clear();
        return dic;
    }
    #endregion
}